/**
 * @Copyright:Copyright (c) 2007 - 2023
 * 
 */
package com.tengtong.db.lang;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Optional;

import com.tengtong.commons.lang.ExceptionUtils;
import com.tengtong.commons.lang.RegexUtils;
import com.tengtong.commons.lang.StringBuilderX;
import com.tengtong.commons.lang.StringUtils;

/**
 * 排序类
 *
 * @author lin_jinming
 * @since: v1.0
 */
public class QuerySortClass {
    
    /**
     * 集合
     *
     *
     * @author lin_jinming
     * @since: v1.0
     */
    public static class Sorts extends LinkedHashSet<Sort> {

        private static final long serialVersionUID = 1L;
                
        /**
         * 
         */
        public Sorts() {
            super();            
        }

        /**
         * @param c
         */
        public Sorts(Collection<? extends Sort> c) {
            super(c);            
        }

        /**
         * @param initialCapacity
         */
        public Sorts(int initialCapacity) {
            super(initialCapacity);            
        }

        public static Sorts of(Sort...sorts) {
            return new Sorts(Arrays.asList(sorts));
        }
        
        /**
         * orders 语法： <field1> [asc|desc][,<field2> [asc|desc],...] <br>
         * 
         * 解析和转换成 Sorts 
         *
         * @param orders
         * @return
         */
        public static Sorts of(String orders) {
            Sorts result = new Sorts();
            if(StringUtils.isNullOrEmpty(orders)) {
                return result;
            }
            
            String[] ss = StringUtils.splitByComma(orders);
            for(var s: ss) {
                result.add(Sort.splitBy(s));
            }
            return result;
        }
        
        @Override
        public String toString() {
            if(size() > 0) {
                StringBuilderX sb = new StringBuilderX();
                forEach(s->{
                    if(sb.length() > 0) {
                        sb.append(",");
                    }
                    sb.append(s.toString());
                });
            }
            return "";
        }
    }
    
    /**
     * 一个排序句子：<fieldName> [Direction] <br>
     * <pre>{@code 
     *    sort.toString(); // 得到符合 sql 语法的排序语句
     * }</pre>
     *
     * @author lin_jinming
     * @since: v1.0
     */
    public static class Sort {
        
        private final String field;
        
        private final Direction dir;
        
        public Sort(String f, Direction d) {
            if(!RegexUtils.isKeyword(f)) {
                throw ExceptionUtils.ofRuntime("语法错误|字段名称不合法 {}", f);
            }
            this.field = f;
            this.dir = d == null ? Direction.ASC:d;
        }
        
        public static Sort of(String field) {
            return of(field, Direction.ASC);
        }
        
        public static Sort of(String field, Direction d) {
            return new Sort(field, d);
        }
        
        public static Sort of(String field, String dir) {
            return of(field, Direction.getDirBy(dir));
        }
        
        public static Sort splitBy(String express) {
            String[] ss = StringUtils.splitBySpaces(express);
            if(ss.length == 1) {
                return of(ss[0]);
            } else {
                return of(ss[0], ss[1]);
            }
        }

        /**
         * @return the field
         */
        public String getField() {
            return field;
        }

        /**
         * @return the dir
         */
        public Direction getDir() {
            return dir;
        }
        
        public String toString() {
            return field + " " + dir.name();
        }
        
    }

    /**
     * 排序方向
     *
     *
     * @author lin_jinming
     * @since: v1.0
     */
    public static enum Direction {
        
        ASC("asc"),         // 顺序
        
        DESC("desc")        // 倒序
        ;
        
        private String dir;
        
        Direction(String dir){
            this.dir = dir;
        }
        
        public String getDirName(){
            return this.dir;
        }
        
        @Override
        public String toString(){
            return getDirName();
        }
        
        public static Direction getDirBy(String name){
            Direction[] ds = values();
            for(Direction d: ds){
                if(d.getDirName().equals(name)){
                    return d;
                }
            }
            return null;
        }
        
        public static Direction fromValue(String string) {
            try {
                return Direction.valueOf(string.toUpperCase(Locale.US));
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format(
                        "Invalid value '%s' for orders given; Has to be either 'desc' or 'asc' (case insensitive)", string), e);
            }
        }
        
        public static Optional<Direction> toOptions(String value){
            try {
                return Optional.of(fromValue(value));
            } catch (IllegalArgumentException e) {
                return Optional.empty();
            }           
        }        
    }
}
